home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / Libraries / DCLAP 4j / DClap / DList.cpp < prev    next >
Encoding:
Text File  |  1995-12-17  |  11.1 KB  |  521 lines  |  [TEXT/R*ch]

  1. // DList.cp
  2. // This code owes it's structure in large part to Apple's MacApp UList unit
  3. // however, d.gilbert has substatially rewritten it.
  4.  
  5.  
  6. #include <ncbi.h>
  7. #include <dgg.h>
  8. #include "DList.h"
  9.  
  10.  
  11. static const short kArrayIncrement = 6;         
  12.  
  13. typedef    DObject* DObjectPtr;
  14.  
  15.  
  16. // class DArray
  17.  
  18.  
  19. DArray::DArray(short itemSize, long initialSize)
  20. {
  21.   SetClass("DArray",sizeof(DArray));
  22.     fArraySize = kEmptySize;
  23.     fArrayIncrement = kArrayIncrement;
  24.     fSize = kEmptySize;
  25.     fArrayStore = NULL;
  26.  
  27.     fItemSize = itemSize;
  28.     fItemSizeShift = 0;
  29.     if (odd(itemSize)) ++itemSize; // make sure we have even size for shifting
  30.     while (((itemSize - 1) >> fItemSizeShift) > 0) ++fItemSizeShift;
  31.     this->SetArraySize(initialSize);
  32.  
  33. DArray::~DArray()
  34. {
  35.     fArrayStore= MemFree(fArrayStore);
  36. }  
  37.  
  38. void DArray::DeleteAll()
  39. {
  40.     if (fSize > kEmptySize) this->DeleteItemsAt(0, fSize); //1,fSize
  41.  
  42. DObject* DArray::Clone()
  43. {
  44.     DArray* result = (DArray*) DObject::Clone();
  45.     result->fArrayStore= MemDup(fArrayStore,  (ulong) (fArraySize << fItemSizeShift));
  46.     return result;
  47. }
  48.  
  49. void* DArray::ComputeAddress(long index)
  50. {
  51.     return (void*) ((char*)fArrayStore + (index << fItemSizeShift)); 
  52. }  
  53.  
  54.  
  55.  
  56. void DArray::DeleteItemsAt(long index, long count)
  57. {
  58.     VoidPtr indexPtr, nextItemPtr, lastItemPtr;
  59.     long countBytes;
  60.  
  61.     countBytes = count << fItemSizeShift;
  62.     indexPtr = this->ComputeAddress(index);
  63.     nextItemPtr = this->ComputeAddress(index + count);
  64.     lastItemPtr = this->ComputeAddress(fSize); //1based: + 1);
  65.  
  66.     if (nextItemPtr < lastItemPtr)        
  67.         MemMove(indexPtr, nextItemPtr, (long)lastItemPtr - (long)nextItemPtr);
  68.  
  69.     this->SetArraySize(fSize - count);        
  70.     fSize -= count;
  71. }   
  72.  
  73.  
  74.  
  75.  
  76. void DArray::GetItemsAt(long index, void* itemPtr, long count)
  77. {
  78.     if (count > kEmptySize)
  79.         MemMove( itemPtr, this->ComputeAddress(index), 
  80.             ((count - 1) << fItemSizeShift) + fItemSize);         
  81. }  
  82.  
  83.  
  84. void DArray::ReplaceItemsAt(long index, void* itemPtr, long count)
  85. {
  86.     VoidPtr indexPtr= this->ComputeAddress(index);
  87.     long countBytes= count << fItemSizeShift;
  88.     MemMove( indexPtr, itemPtr, countBytes);
  89.  
  90.  
  91. void DArray::InsertItemsBefore(long index, void* itemPtr, long count)
  92. {
  93.     VoidPtr indexPtr, nextIndexPtr, lastItemPtr;
  94.     long countBytes;
  95.  
  96.     this->SetArraySize(fSize + count);                 
  97.     indexPtr = this->ComputeAddress(index);
  98.     nextIndexPtr = this->ComputeAddress(index + count);
  99.     lastItemPtr = this->ComputeAddress(fSize);    //1based: fSize + 1
  100.     countBytes = count << fItemSizeShift;
  101.  
  102.     if (index < fSize)        //1based: <=             
  103.         MemMove( nextIndexPtr, indexPtr, (long)lastItemPtr - (long)indexPtr);
  104.  
  105.     if ((countBytes == sizeof(long)) && !odd((long)itemPtr) && !odd((long)indexPtr))
  106.         *((long*)indexPtr) = *((long*)itemPtr);        // shortcut for longs 
  107.     else
  108.         MemMove(indexPtr, itemPtr, countBytes); 
  109.  
  110.     fSize += count;
  111. }  
  112.  
  113.  
  114.  
  115.  
  116. void DArray::SetArraySize(long theSize)
  117. {
  118.     long newSize;
  119.     
  120.     if ((theSize > fArraySize) || (fArraySize - theSize >= fArrayIncrement)) {
  121.         if (fArrayIncrement)
  122.             newSize = (theSize + fArrayIncrement) 
  123.                                 - (theSize + fArrayIncrement) % fArrayIncrement;
  124.         else
  125.             newSize = theSize;
  126.         if (newSize != fArraySize)  {
  127.             ulong chunk= (ulong) (newSize << fItemSizeShift);
  128.             if (fArrayStore == NULL) fArrayStore = MemNew( chunk);
  129.             else fArrayStore= MemMore(fArrayStore, chunk);
  130.             }
  131.         fArraySize = newSize;
  132.       }
  133.  
  134.  
  135. long DArray::Search(CompareFunc compare, void *itemPtr)
  136. {
  137.     register char*  itemAt = (char*) fArrayStore;
  138.     long     itemsize= 1 << fItemSizeShift;
  139.         
  140.         // speed this up w/ a bisection method == start in middle & bounce around ??
  141.         // NO -- can't assume this array is SORTED !!
  142. #if 0
  143.     long lo, hi, mid;
  144.     short cmp;
  145.     lo= 0; 
  146.     hi= fSize;
  147.     do {
  148.         mid= (hi+lo) >> 1;  // div 2;
  149.         itemAt= (char*) fArrayStore + mid * itemsize;
  150.         cmp= (*compare)( itemPtr, itemAt);
  151.         if (cmp == 0) return mid;
  152.         else if (cmp > 0) lo= mid;
  153.         else hi= mid;
  154.     } while (hi > lo+1);
  155.     
  156.     if (mid != hi) {
  157.         itemAt= (char*) fArrayStore + hi * itemsize;
  158.         cmp= (*compare)( itemPtr, itemAt);
  159.         if (cmp == 0) return hi;
  160.         }
  161.     else if (mid != lo) {
  162.         itemAt= (char*) fArrayStore + lo * itemsize;
  163.         cmp= (*compare)( itemPtr, itemAt);
  164.         if (cmp == 0) return lo;
  165.         }
  166.     return kEmptyIndex;
  167. #else
  168.     register long i;
  169.     for (i = 0; i < fSize; i++) {
  170.         if ( (*compare)( itemPtr, itemAt) == 0) 
  171.             return i;
  172.         itemAt += itemsize;
  173.         }
  174.     return kEmptyIndex;
  175. #endif
  176. }     
  177.  
  178.  
  179.  
  180.  
  181.  
  182.  
  183.  
  184. // class DList
  185.  
  186. // default fCompareFunc
  187. short DefaultCompare(void* item1, void* item2)
  188. {
  189.     if ((unsigned long) item1 > (unsigned long) item2)
  190.         return 1;
  191.     else if ((unsigned long) item1 < (unsigned long) item2)
  192.         return -1;
  193.     else
  194.         return 0;
  195.  
  196.  
  197. DList::DList(CompareFunc itsComparer, short options): 
  198.     DArray(sizeof(DObject*), kEmptySize)
  199. {
  200.   SetClass("DList",sizeof(DList));
  201.     if (itsComparer) fCompareFunc= itsComparer;
  202.     else fCompareFunc= ::DefaultCompare;
  203.     fOwnObjects= options & kOwnObjects;
  204.     fDeleteObjects = options & kDeleteObjects;        
  205.  
  206. DList::~DList()
  207. {
  208.     if (fDeleteObjects) this->FreeAllObjects();
  209.  
  210.         
  211. DObject* DList::At(long index)
  212. {
  213.     //return (*this)[index];
  214.     if (index<0 || index>=fSize) return NULL;
  215.     DObject** vp= (DObject**) ((char*)fArrayStore + (index << fItemSizeShift)); 
  216.     if (vp) return *vp;
  217.     else return NULL;
  218.  
  219.  
  220.  
  221. void DList::FreeAllObjects()
  222. {
  223.     long i, n= this->GetSize();
  224.     for (i= 0; i<n; i++) {
  225.         DObject* obj= At(i);
  226.         if (obj) {
  227.           if (obj->GetOwnerCount() <= 1) delete obj;
  228.           else obj->suicide(); // this alone doens't call obj destructors !!
  229.           }
  230.         }
  231.     this->DeleteAll();
  232.  
  233.  
  234. long DList::GetEqualItemNo(DObject* item)
  235. {
  236.     long index;
  237.  
  238.     if (item == NULL) return kEmptyIndex;
  239.     index = this->Search( fCompareFunc, &item);
  240.     return index;  // == kEmptyIndex if no match
  241.  
  242.  
  243.  
  244. #if 1
  245. // choose your sort
  246.  
  247. void DList::QuickSort(long beginIndex, long endIndex, CompareFunc CompareItems)
  248. // recursive qs
  249. {
  250.     long i, j;
  251.      DObjectPtr    iobj, jobj, endobj;
  252.      
  253.     if (beginIndex < endIndex) {
  254.         i = beginIndex; 
  255.         j = endIndex;  
  256.         endobj= this->At(endIndex);
  257.         do {
  258.             iobj= this->At(i);            
  259.             while (i < j && CompareItems( iobj, endobj) <= 0) 
  260.                 iobj= this->At(++i);            
  261.             jobj= this->At(j);
  262.             while (j > i && CompareItems( jobj, endobj) >= 0) 
  263.                 jobj= this->At(--j);
  264.             if (i<j) {    // swap
  265.                 this->ReplaceItemsAt(i, &jobj, 1); //was &     
  266.                 this->ReplaceItemsAt(j, &iobj, 1); //was &     
  267.                 }
  268.         } while (i < j);
  269.         
  270.          this->ReplaceItemsAt(i, &endobj, 1);  
  271.         this->ReplaceItemsAt(endIndex, &iobj, 1);  
  272.         if (i - beginIndex < endIndex - i) {
  273.             QuickSort( beginIndex, i-1, CompareItems);
  274.           QuickSort( i+1, endIndex, CompareItems);
  275.           }
  276.         else {
  277.             QuickSort( i+1, endIndex, CompareItems);
  278.              QuickSort( beginIndex, i-1, CompareItems);
  279.              }
  280.         }
  281. }
  282.  
  283. long DList::QSPartition(long beginIndex, long endIndex,     
  284.                                    CompareFunc CompareItems)
  285. {
  286.     return 0;
  287. }
  288.  
  289. long DList::QSRandomPartition(long beginIndex, long endIndex,     
  290.                                    CompareFunc CompareItems)
  291. {
  292.     return 0;
  293. }
  294.  
  295.  
  296. #else
  297. // this was Apple's algorithm
  298.  
  299. void DList::QuickSort(long beginIndex, long endIndex, CompareFunc CompareItems)
  300. {
  301.     if (beginIndex < endIndex) {
  302.         long left = this->QSRandomPartition(beginIndex, endIndex, CompareItems);
  303.         this->QuickSort(beginIndex, left, CompareItems);
  304.         this->QuickSort(left+1, endIndex, CompareItems);     
  305.     }
  306.  
  307.  
  308. long DList::QSPartition(long beginIndex, long endIndex, CompareFunc CompareItems)
  309. {
  310.     if (beginIndex >= endIndex)
  311.         return endIndex;
  312.     {
  313.         DObjectPtr pivot = this->At(beginIndex);                // x
  314.         long i = beginIndex - 1;    // p - 1
  315.         long j = endIndex + 1;    // r + 1
  316.         while (true)
  317.         {
  318.             DObjectPtr secondKey;
  319.             do
  320.             {
  321.                 --j;
  322.                 secondKey = this->At(j);    // A[j]
  323.             } while (CompareItems( pivot, secondKey) <= -1);
  324.             do
  325.             {
  326.                 ++i;
  327.                 secondKey = this->At(i);    // A[i]
  328.             } while (CompareItems( pivot, secondKey) >= 1);
  329.             if (i < j)
  330.             {    // Swap the Items
  331.                 DObjectPtr leftObject = this->At(i);
  332.                 DObjectPtr rightObject = this->At(j);
  333.                 this->ReplaceItemsAt(i, &rightObject, 1); // was &
  334.                 this->ReplaceItemsAt(j, &leftObject, 1); //was &
  335.             }
  336.             else
  337.                 return j;
  338.         }
  339.     }
  340.  
  341.  
  342. long RandomArrayIndex(long beginIndex, long endIndex)
  343. {
  344.     if (beginIndex == endIndex) return beginIndex;
  345.     //long randomValue = rand() % labs(endIndex - beginIndex);// labs() not found by g++
  346.     long randomValue = endIndex - beginIndex;
  347.     if (randomValue < 0) randomValue = -randomValue;
  348.     randomValue= rand() % randomValue;
  349.     return beginIndex + randomValue;
  350. }
  351.  
  352. long DList::QSRandomPartition(long beginIndex, long endIndex, CompareFunc CompareItems )
  353. {
  354.     long i = RandomArrayIndex(beginIndex, endIndex);
  355.     
  356.     // exchange
  357.     DObjectPtr beginIndexObject = this->At(beginIndex);
  358.     DObjectPtr ithObject = this->At(i);
  359.     this->ReplaceItemsAt(beginIndex, &ithObject, 1); //was &    // A[beginIndex] = A[i]
  360.     this->ReplaceItemsAt(i, &beginIndexObject, 1); //was &    // A[i] = A[beginIndex]
  361.  
  362.     return this->QSPartition(beginIndex, endIndex, CompareItems);
  363.  
  364. #endif
  365.  
  366.  
  367. void DList::Sort()
  368. {
  369.     if (this->GetSize() > 0)
  370.         this->QuickSort(0, fSize-1, fCompareFunc); // was 1,fsize
  371.  
  372. void DList::SortBy(CompareFunc CompareItems)
  373. {
  374.     if (this->GetSize() > 0)
  375.         this->QuickSort(0, fSize-1, CompareItems); // was 1,fsize
  376.  
  377.  
  378. void DList::AtDelete(long index)
  379. {
  380.     if (fDeleteObjects)  At(index)->suicide(); //delete At(index); 
  381.         // ^^ this will make a mess of Pop() and Dequeue() method results, who call here
  382.     this->DeleteItemsAt(index, 1);
  383. }
  384.  
  385. void DList::Delete(DObject* item)
  386. {
  387.     long index;
  388.     if (item == NULL) return;
  389.     index = this->GetIdentityItemNo(item);
  390.     if (index != kEmptyIndex) this->AtDelete(index);
  391.  
  392.  
  393. DObject* DList::First()
  394. {
  395.     if (fSize <= kEmptySize)
  396.         return NULL;
  397.     else
  398.         return this->At(0); //1based: 1
  399.  
  400. DObject* DList::Last()
  401. {
  402.     if (fSize <= kEmptySize)
  403.         return NULL;
  404.     else
  405.         return this->At(fSize-1);
  406. }  
  407.  
  408.  
  409. long DList::GetIdentityItemNo(DObject* item)
  410. {
  411.     if (item == NULL) return kEmptyIndex;
  412.     long i, n= this->GetSize();
  413.     for (i= 0; i<n; i++) if (At(i) == item) return i;
  414.     return kEmptyIndex; 
  415.  
  416.  
  417. void DList::AtPut(long index, DObject* newItem)
  418. {
  419.     if (fOwnObjects && newItem) newItem->newOwner();
  420.     this->ReplaceItemsAt( index, &newItem, 1); //was &newItem
  421.  
  422.  
  423. void DList::InsertBefore(long index, DObject* item)
  424. {
  425.     if (fOwnObjects && item) item->newOwner();
  426.     this->InsertItemsBefore(index, &item, 1); // was &item !!!
  427. }
  428.  
  429.  
  430. void DList::InsertInOrder(DObject* item)
  431. {
  432.     long index= Search( fCompareFunc, &item);
  433.     if (index > kEmptyIndex)
  434.         InsertBefore( index, item);
  435.     else
  436.         InsertBefore( fSize, item);
  437.  
  438. void DList::InsertFirst(DObject* item)
  439. {
  440.     this->InsertBefore(0, item); //1
  441.  
  442. void DList::InsertLast(DObject* item)
  443. {
  444.     this->InsertBefore(fSize, item); // + 1
  445.  
  446.  
  447. void DList::Push(DObject* item)
  448. {
  449.     this->InsertLast(item);
  450.  
  451. DObject* DList::Pop()
  452. {
  453.     DObject* topOfStack;
  454.  
  455.     if (fSize <= kEmptySize)
  456.         topOfStack = NULL;
  457.     else {
  458.         topOfStack = this->At(fSize-1);
  459.         //this->AtDelete(fSize-1);
  460.         this->DeleteItemsAt(fSize-1, 1);     // this bypasses fDeleteObjects check ...
  461.         }
  462.     return topOfStack;
  463.  
  464.  
  465.  
  466. void DList::Queue(DObject* item)
  467. {
  468.     this->InsertLast(item);
  469.  
  470. DObject* DList::Dequeue()
  471. {
  472.     DObject* beginningOfStack;
  473.  
  474.     if (fSize <= kEmptySize)
  475.         beginningOfStack = NULL;
  476.     else {
  477.         beginningOfStack = this->At(0);    //1based: 1
  478.         //this->AtDelete(0);                 //1based: 1
  479.         this->DeleteItemsAt(0, 1);     // this bypasses fDeleteObjects check ...
  480.         }
  481.     return beginningOfStack;
  482.  
  483.  
  484.  
  485.  
  486.  
  487. DList*    FreeListIfObject(DList* aList)
  488. {
  489.     if (aList) {
  490.         //aList->FreeAllObjects(); // destructor now calls FreeAllObjects()
  491.         delete aList; 
  492.         }
  493.     return NULL;
  494. }
  495.